#include "osEvent.h"

#include "osCpu.h"

/*****************************************************************************
 * @function        vEventInit
 * @brief 			事件控制块初始化函数.
 *  
 * @param[in] 		event 事件控制块指针.
 * @param[in]       type  事件的类型.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void     vEventInit(EVENT_T *event, EVENT_TYPE_T type)
{
    event->type = type;
    vListInit( &(event->waitList));
}



/*****************************************************************************
 * @function        vEventWait
 * @brief 			等待事件. 任务从就绪运行 进入事件等待状态，当事件到来或者超时时进入就绪态
 *  
 * @param[in] 		event   事件控制块.
 * @param[in]       task    要等待的任务.
 * @param[in] 	    msg     待说明...
 * @param[in]       state   事件标志(仅高16位有效)
 * @param[in]       timeout 超时等待时间
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void     vEventWait(EVENT_T *event, TASK_T *task, void *msg, uint32_t state, uint32_t timeout)
{
    uint32_t primask = vTaskEnterCritical();

    task->waitEvent = event;                // 记录任务发生的事件控制块
    task->eventMsg = msg;                   // 记录事件消息
    task->waitEventResult = OS_NOERROR;     // 事件结果
    task->state |= (state & OS_TASK_STA_WAIT_MASK); // 记录事件类型（bit 23- bit 16 ）
    
    /* 将任务从就绪队列中移除*/
    vTaskReadyListDel(task);
    
    /* 将任务插入到事件队列的尾部*/
    vListAddLast(&(event->waitList), &(task->taskLinkNode));
    
    /* 如果设置的超时等待时间，则还需要将任务插入到阻塞队列中*/
    if (timeout)
    {
        vTaskDelayListAdd(task, timeout);
    }
    
    vTaskExitCritical(primask);
}


/*****************************************************************************
 * @function        vEventWait
 * @brief 			事件唤醒. 唤醒事件队列中首个任务。
 *  
 * @param[in] 		event   事件控制块.
 * @param[in] 	    msg     待说明...
 * @param[in]       result  事件的结果
 * 
 * @return 			被唤醒的任务.	
 *
 * ***************************************************************************/
TASK_T * vEventWakeUp(EVENT_T *event, void *msg, uint32_t result)
{
    NODE_T *node;
    TASK_T *task = (TASK_T *)0;
    
    uint32_t primask = vTaskEnterCritical();
    
    node = vListRemoveFirst(&(event->waitList));
    
    /* 事件队列存在节点*/
    if (node != (NODE_T *)0)
    {
        task = container_of(node, TASK_T, taskLinkNode);    // 获得任务控制块
        task->waitEvent = (EVENT_T *)0;                     // 清除任务所属事件队列
        task->eventMsg = msg;                               // 记录任务事件消息
        task->waitEventResult = result;                     // 记录任务事件结果
        task->state &= ~(OS_TASK_STA_WAIT_MASK);             // 清除任务事件标志
        
        /* 任务同时在阻塞队列中*/
        if (task->delayTicks != 0)
        {
            /* 将任务从阻塞队列中移除*/
            vTaskDelayListDel(task);
        }
        
        /* 将任务添加至就绪队列中*/
        vTaskReadyListAdd(task);
    }
    
    
    vTaskExitCritical(primask);
    
    return task;
}

/*****************************************************************************
 * @function        vEventWakeUpTask
 * @brief 			事件唤醒指定任务. 
 *  
 * @param[in] 		event   事件控制块.
 * @param[in]       task    待唤醒的任务
 * @param[in] 	    msg     待说明...
 * @param[in]       result  事件的结果
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vEventWakeUpTask(EVENT_T *event, TASK_T *task, void *msg, uint32_t result)
{
    uint32_t primask = vTaskEnterCritical();
    
    vEventRemoveTask(task, msg, result);
        
    /* 任务同时在阻塞队列中*/
    if (task->delayTicks != 0)
    {
        /* 将任务从阻塞队列中移除*/
        vTaskDelayListDel(task);
    }
        
    /* 将任务添加至就绪队列中*/
    vTaskReadyListAdd(task);

    vTaskExitCritical(primask);
}

/*****************************************************************************
 * @function        vEventRemoveTask
 * @brief 			移除事件队列中的任务(超时时使用)。
 *  
 * @param[in] 		task    要移除的任务.
 * @param[in] 	    msg     待说明...
 * @param[in]       result  事件的结果
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vEventRemoveTask(TASK_T *task, void *msg, uint32_t result)
{
    uint32_t primask = vTaskEnterCritical();
    
    /* 将任务从事件队列中移除*/
    vListRemove(&(task->waitEvent->waitList), &(task->taskLinkNode));
    
    task->waitEvent = (EVENT_T *)0;                     // 清除任务所属事件队列
    task->eventMsg = msg;                               // 获取任务事件消息
    task->waitEventResult = result;                     // 获取任务事件结果
    task->state &= ~(OS_TASK_STA_WAIT_MASK);             // 清除任务事件标志
    
    vTaskExitCritical(primask);
}

/*****************************************************************************
 * @function        vEventRemoveTask
 * @brief 			移除事件队列中的所有任务，所有任务都进入就绪态
 *  
 * @param[in] 		event   待清空的事件控制块.
 * @param[in] 	    msg     待说明...
 * @param[in]       result  事件的结果
 * 
 * @return 			清空任务的数量.	
 *
 * ***************************************************************************/
uint32_t vEventRemoveAll (EVENT_T *event, void *msg, uint32_t result)
{
    NODE_T *node;
    TASK_T *task;
    uint32_t count;
    
    uint32_t primask = vTaskEnterCritical();
    
    count = vListCount(&(event->waitList));
    
    while( (node = vListRemoveFirst(&(event->waitList))) != (NODE_T *)0)
    {
        /* 将任务从事件队列中移除*/
        task = container_of(node, TASK_T, taskLinkNode);
        
        task->waitEvent = (EVENT_T *)0;                     // 清除任务所属事件队列
        task->eventMsg = msg;                               // 获取任务事件消息
        task->waitEventResult = result;                     // 获取任务事件结果
        task->state &= ~(OS_TASK_STA_WAIT_MASK);             // 清除任务事件标志
        
        /* 任务同时在阻塞队列中*/
        if (task->delayTicks != 0)
        {
            /* 将任务从阻塞队列中移除*/
            vTaskDelayListDel(task);
        }
        
        /* 将任务添加至就绪队列中*/
        vTaskReadyListAdd(task);
    }
    
    
    vTaskExitCritical(primask);
    
    return count;
}


/*****************************************************************************
 * @function        vEventWaitCount
 * @brief 			获取等待事件的个数
 *  
 * @param[in] 		event   待查询的事件控制块.
 * 
 * @return 			等待的任务数量.	
 *
 * ***************************************************************************/
uint32_t vEventWaitCount(EVENT_T *event)
{
    uint32_t count;
    uint32_t primask = vTaskEnterCritical();
 
    count = vListCount(&(event->waitList));
    
    vTaskExitCritical(primask);
    
    return count;    
}


